package utils

import (
	"net/http"
	"reflect"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
)

// 处理json表单数据验证
func ValidateJsonBody(c *gin.Context, obj interface{}) bool {
	if err := c.ShouldBindJSON(obj); err != nil {
		validateReq(c, err)
		return false
	}
	return true
}

// 处理form表单数据验证
func ValidateForm(c *gin.Context, obj interface{}) bool {
	if err := c.ShouldBind(obj); err != nil {
		validateReq(c, err)
		return false
	}
	return true
}

// 处理api/v1/user?name=xxx&age=xxx 请求参数的校验
func ValidateParams(c *gin.Context, obj interface{}) bool {
	if err := c.ShouldBindQuery(obj); err != nil {
		validateReq(c, err)
		return false
	}
	return true
}

func validateReq(c *gin.Context, err error) {
	validationErrors, ok := err.(validator.ValidationErrors)
	if ok {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": validationErrors.Error(),
		})
	} else {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
	}
	c.Abort() // 中断请求
}

// 设置默认值的通用函数
func SetDefaults(obj interface{}) {
	v := reflect.ValueOf(obj).Elem()
	setDefaultsRecursive(v)
}

func setDefaultsRecursive(v reflect.Value) {
	// 处理指针类型
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	// 处理结构体类型
	if v.Kind() == reflect.Struct {
		t := v.Type()

		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			value := v.Field(i)

			// 处理嵌套结构体
			if value.Kind() == reflect.Struct && field.Anonymous {
				setDefaultsRecursive(value)
				continue
			}

			// 处理字段默认值
			if tagValue, ok := field.Tag.Lookup("default"); ok && value.CanSet() {
				if value.IsZero() {
					switch value.Kind() {
					case reflect.String:
						value.SetString(tagValue)
					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
						if intValue, err := strconv.ParseInt(tagValue, 10, 64); err == nil {
							value.SetInt(intValue)
						}
					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
						if uintValue, err := strconv.ParseUint(tagValue, 10, 64); err == nil {
							value.SetUint(uintValue)
						}
					case reflect.Float32, reflect.Float64:
						if floatValue, err := strconv.ParseFloat(tagValue, 64); err == nil {
							value.SetFloat(floatValue)
						}
					case reflect.Bool:
						if boolValue, err := strconv.ParseBool(tagValue); err == nil {
							value.SetBool(boolValue)
						}
						// 这里可以添加更多类型处理
					}
				}
			}
		}
	}
}
